using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;

namespace LockImage.Utils
{
    public class ResourceManager
    {
        private static String RESOURCE_NAME = "IMAGE_FILE";
        private static String RESOURCE_TYPE = "FILE";


        private const int LOAD_LIBRARY_AS_DATAFILE = 0x2;


        #region DllImport

        /// <summary>
        /// BeginUpdateResource
        /// </summary>
        /// <param name="pFileName"></param>
        /// <param name="bDeleteExistingResources"></param>
        /// <returns></returns>
        [DllImport("kernel32", CharSet = CharSet.Unicode)]
        private static extern IntPtr BeginUpdateResource(String pFileName, 
                                                         bool bDeleteExistingResources);

        /// <summary>
        /// UpdateResource
        /// </summary>
        /// <param name="hUpdate"></param>
        /// <param name="lpType"></param>
        /// <param name="lpName"></param>
        /// <param name="wLanguage"></param>
        /// <param name="lpData"></param>
        /// <param name="cbData"></param>
        /// <returns></returns>
        [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int UpdateResource(IntPtr hUpdate,
                               System.Text.StringBuilder lpType, 
                               System.Text.StringBuilder lpName, 
                                                Int16 wLanguage, 
                                                  Byte[] lpData, 
                                                     int cbData);

        /// <summary>
        /// EndUpdateResource
        /// </summary>
        /// <param name="hUpdate"></param>
        /// <param name="fDiscard"></param>
        /// <returns></returns>
        [DllImport("kernel32", SetLastError = true)]
        private static extern int EndUpdateResource(IntPtr hUpdate, bool fDiscard);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="lpLibFileName"></param>
        /// <param name="hFile"></param>
        /// <param name="dwFlags"></param>
        /// <returns></returns>
        [DllImport("kernel32", CharSet = CharSet.Auto)]
        private extern static IntPtr LoadLibraryEx(
           [MarshalAs(UnmanagedType.LPTStr)]
         string lpLibFileName,
           IntPtr hFile,
           int dwFlags);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hLibModule"></param>
        /// <returns></returns>
        [DllImport("kernel32")]
        private extern static int FreeLibrary(
           IntPtr hLibModule);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hInstance"></param>
        /// <param name="hResInfo"></param>
        /// <returns></returns>
        [DllImport("kernel32")]
        private extern static IntPtr LoadResource(
           IntPtr hInstance,
           IntPtr hResInfo);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hResData"></param>
        /// <returns></returns>
        [DllImport("kernel32")]
        private extern static IntPtr LockResource(
           IntPtr hResData);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hInstance"></param>
        /// <param name="lpName"></param>
        /// <param name="lpType"></param>
        /// <returns></returns>
        [DllImport("kernel32", CharSet = CharSet.Auto)]
        private extern static IntPtr FindResource(
           IntPtr hInstance,
           [MarshalAs(UnmanagedType.LPTStr)]
           string lpName,
           string lpType);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hInstance"></param>
        /// <param name="hResInfo"></param>
        /// <returns></returns>
        [DllImport("kernel32")]
        private extern static int SizeofResource(
           IntPtr hInstance,
           IntPtr hResInfo);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hResData"></param>
        /// <returns></returns>
        [DllImport("kernel32")]
        private extern static int FreeResource(
           IntPtr hResData);
        #endregion

        #region Resource Methods

        public static Byte[] LoadResource(String libFile)
        {
            Byte[] resAsByteArray = null;


            IntPtr hLibrary = LoadLibraryEx(
               libFile,
               IntPtr.Zero,
               LOAD_LIBRARY_AS_DATAFILE);
            if (IntPtr.Zero == hLibrary)
            {
                throw new Exception("IntPtr.Zero == hLibrary");
            }
           
            if (hLibrary != IntPtr.Zero)
            {
                IntPtr hResource = FindResource(hLibrary,
                           ResourceManager.RESOURCE_NAME,
                           ResourceManager.RESOURCE_TYPE);

                //if (IntPtr.Zero == hResource)
                //{
                //    throw new Exception("IntPtr.Zero == hResource");
                //}

                if (IntPtr.Zero != hResource)
                {

                    IntPtr hData = LoadResource(hLibrary, hResource);
                    if (IntPtr.Zero == hData)
                    {
                        throw new Exception("IntPtr.Zero != hData");

                    }
                    if (IntPtr.Zero != hData)
                    {
                        IntPtr lpData = LockResource(hData);
                        int lDataSize = SizeofResource(hLibrary, hResource);
                        resAsByteArray = new Byte[lDataSize];
                        Marshal.Copy(lpData, resAsByteArray, 0, lDataSize);
                        FreeResource(hData);
                    }
                }
            }
            return resAsByteArray;
        }

        public static void UpdateResource(String libPath, String resourcePath)
        {
            IntPtr hResource = BeginUpdateResource(libPath, false);
            System.IO.FileStream resFileStream =
            new System.IO.FileStream(resourcePath, System.IO.FileMode.Open);
            
            System.IO.BinaryReader fileReader =
            new System.IO.BinaryReader(resFileStream);

            Byte[] resAsbyteArray = fileReader.ReadBytes((int)resFileStream.Length);

            UpdateResource(hResource, 
                new StringBuilder(ResourceManager.RESOURCE_TYPE), 
                new StringBuilder(ResourceManager.RESOURCE_NAME), 
                                         1033, 
                               resAsbyteArray,
                        resAsbyteArray.Length);

            EndUpdateResource(hResource, false);
            fileReader.Close();
            resFileStream.Close();
       
        }


        #endregion

    }
}
